home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / include / asm / semaphore.h < prev    next >
C/C++ Source or Header  |  2005-10-13  |  5KB  |  198 lines

  1. #ifndef _I386_SEMAPHORE_H
  2. #define _I386_SEMAPHORE_H
  3.  
  4. #include <linux/wait.h>
  5. #include <linux/linkage.h>
  6.  
  7. /*
  8.  * SMP- and interrupt-safe semaphores..
  9.  *
  10.  * (C) Copyright 1996 Linus Torvalds
  11.  *
  12.  * Modified 1996-12-23 by Dave Grothe <dave@gcom.com> to fix bugs in
  13.  *                     the original code and to make semaphore waits
  14.  *                     interruptible so that processes waiting on
  15.  *                     semaphores can be killed.
  16.  * Modified 1999-02-14 by Andrea Arcangeli, split the sched.c helper
  17.  *               functions in asm/sempahore-helper.h while fixing a
  18.  *               potential and subtle race discovered by Ulrich Schmid
  19.  *               in down_interruptible(). Since I started to play here I
  20.  *               also implemented the `trylock' semaphore operation.
  21.  *          1999-07-02 Artur Skawina <skawina@geocities.com>
  22.  *                     Optimized "0(ecx)" -> "(ecx)" (the assembler does not
  23.  *                     do this). Changed calling sequences from push/jmp to
  24.  *                     traditional call/ret.
  25.  * Modified 2001-01-01 Andreas Franck <afranck@gmx.de>
  26.  *               Some hacks to ensure compatibility with recent
  27.  *               GCC snapshots, to avoid stack corruption when compiling
  28.  *               with -fomit-frame-pointer. It's not sure if this will
  29.  *               be fixed in GCC, as our previous implementation was a
  30.  *               bit dubious.
  31.  *
  32.  * If you would like to see an analysis of this implementation, please
  33.  * ftp to gcom.com and download the file
  34.  * /pub/linux/src/semaphore/semaphore-2.0.24.tar.gz.
  35.  *
  36.  */
  37.  
  38. #include <asm/system.h>
  39. #include <asm/atomic.h>
  40. #include <linux/wait.h>
  41. #include <linux/rwsem.h>
  42.  
  43. struct semaphore {
  44.     atomic_t count;
  45.     int sleepers;
  46.     wait_queue_head_t wait;
  47. };
  48.  
  49.  
  50. #define __SEMAPHORE_INITIALIZER(name, n)                \
  51. {                                    \
  52.     .count        = ATOMIC_INIT(n),                \
  53.     .sleepers    = 0,                        \
  54.     .wait        = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait)    \
  55. }
  56.  
  57. #define __MUTEX_INITIALIZER(name) \
  58.     __SEMAPHORE_INITIALIZER(name,1)
  59.  
  60. #define __DECLARE_SEMAPHORE_GENERIC(name,count) \
  61.     struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
  62.  
  63. #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
  64. #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
  65.  
  66. static inline void sema_init (struct semaphore *sem, int val)
  67. {
  68. /*
  69.  *    *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
  70.  *
  71.  * i'd rather use the more flexible initialization above, but sadly
  72.  * GCC 2.7.2.3 emits a bogus warning. EGCS doesn't. Oh well.
  73.  */
  74.     atomic_set(&sem->count, val);
  75.     sem->sleepers = 0;
  76.     init_waitqueue_head(&sem->wait);
  77. }
  78.  
  79. static inline void init_MUTEX (struct semaphore *sem)
  80. {
  81.     sema_init(sem, 1);
  82. }
  83.  
  84. static inline void init_MUTEX_LOCKED (struct semaphore *sem)
  85. {
  86.     sema_init(sem, 0);
  87. }
  88.  
  89. fastcall void __down_failed(void /* special register calling convention */);
  90. fastcall int  __down_failed_interruptible(void  /* params in registers */);
  91. fastcall int  __down_failed_trylock(void  /* params in registers */);
  92. fastcall void __up_wakeup(void /* special register calling convention */);
  93.  
  94. fastcall void __down(struct semaphore * sem);
  95. fastcall int  __down_interruptible(struct semaphore * sem);
  96. fastcall int  __down_trylock(struct semaphore * sem);
  97. fastcall void __up(struct semaphore * sem);
  98.  
  99. /*
  100.  * This is ugly, but we want the default case to fall through.
  101.  * "__down_failed" is a special asm handler that calls the C
  102.  * routine that actually waits. See arch/i386/kernel/semaphore.c
  103.  */
  104. static inline void down(struct semaphore * sem)
  105. {
  106.     might_sleep();
  107.     __asm__ __volatile__(
  108.         "# atomic down operation\n\t"
  109.         LOCK "decl %0\n\t"     /* --sem->count */
  110.         "js 2f\n"
  111.         "1:\n"
  112.         LOCK_SECTION_START("")
  113.         "2:\tlea %0,%%eax\n\t"
  114.         "call __down_failed\n\t"
  115.         "jmp 1b\n"
  116.         LOCK_SECTION_END
  117.         :"=m" (sem->count)
  118.         :
  119.         :"memory","ax");
  120. }
  121.  
  122. /*
  123.  * Interruptible try to acquire a semaphore.  If we obtained
  124.  * it, return zero.  If we were interrupted, returns -EINTR
  125.  */
  126. static inline int down_interruptible(struct semaphore * sem)
  127. {
  128.     int result;
  129.  
  130.     might_sleep();
  131.     __asm__ __volatile__(
  132.         "# atomic interruptible down operation\n\t"
  133.         LOCK "decl %1\n\t"     /* --sem->count */
  134.         "js 2f\n\t"
  135.         "xorl %0,%0\n"
  136.         "1:\n"
  137.         LOCK_SECTION_START("")
  138.         "2:\tlea %1,%%eax\n\t"
  139.         "call __down_failed_interruptible\n\t"
  140.         "jmp 1b\n"
  141.         LOCK_SECTION_END
  142.         :"=a" (result), "=m" (sem->count)
  143.         :
  144.         :"memory");
  145.     return result;
  146. }
  147.  
  148. /*
  149.  * Non-blockingly attempt to down() a semaphore.
  150.  * Returns zero if we acquired it
  151.  */
  152. static inline int down_trylock(struct semaphore * sem)
  153. {
  154.     int result;
  155.  
  156.     __asm__ __volatile__(
  157.         "# atomic interruptible down operation\n\t"
  158.         LOCK "decl %1\n\t"     /* --sem->count */
  159.         "js 2f\n\t"
  160.         "xorl %0,%0\n"
  161.         "1:\n"
  162.         LOCK_SECTION_START("")
  163.         "2:\tlea %1,%%eax\n\t"
  164.         "call __down_failed_trylock\n\t"
  165.         "jmp 1b\n"
  166.         LOCK_SECTION_END
  167.         :"=a" (result), "=m" (sem->count)
  168.         :
  169.         :"memory");
  170.     return result;
  171. }
  172.  
  173. /*
  174.  * Note! This is subtle. We jump to wake people up only if
  175.  * the semaphore was negative (== somebody was waiting on it).
  176.  * The default case (no contention) will result in NO
  177.  * jumps for both down() and up().
  178.  */
  179. static inline void up(struct semaphore * sem)
  180. {
  181.     __asm__ __volatile__(
  182.         "# atomic up operation\n\t"
  183.         LOCK "incl %0\n\t"     /* ++sem->count */
  184.         "jle 2f\n"
  185.         "1:\n"
  186.         LOCK_SECTION_START("")
  187.         "2:\tlea %0,%%eax\n\t"
  188.         "call __up_wakeup\n\t"
  189.         "jmp 1b\n"
  190.         LOCK_SECTION_END
  191.         ".subsection 0\n"
  192.         :"=m" (sem->count)
  193.         :
  194.         :"memory","ax");
  195. }
  196.  
  197. #endif
  198.